package com.xian.im.modules.im.core.impl;

import cn.hutool.core.bean.BeanUtil;
import com.xian.feign.UserChannelClient;
import com.xian.im.common.constant.EhcacheConstant;
import com.xian.im.common.enums.UniqueTypeGenerateEnums;
import com.xian.im.common.exception.BusinessException;
import com.xian.im.common.model.dto.AccountDto;
import com.xian.im.common.model.dto.GroupUserDto;
import com.xian.im.common.model.dto.UserDto;
import com.xian.im.common.model.from.UserFrom;
import com.xian.im.common.model.session.SessionUser;
import com.xian.im.common.model.vo.UserVo;
import com.xian.im.common.sequence.UniqueSnowFlakeGenerate;
import com.xian.im.common.utils.bussiness.ChannelClientContextUtil;
import com.xian.im.modules.im.core.IGroupUserCoreService;
import com.xian.im.modules.im.core.IUserCoreService;
import com.xian.im.modules.im.entity.AccountEntity;
import com.xian.im.modules.im.entity.UserEntity;
import com.xian.im.modules.im.service.AccountService;
import com.xian.im.modules.im.service.UserService;
import com.xian.im.modules.security.TokenProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

/**
 * @program: xian-code
 * @description:
 * @author: liru.xian
 * @create: 2021-01-19 19:07
 **/
@Slf4j
@Service
public class IUserCoreServiceImpl implements IUserCoreService {

    @Resource
    private UserService userService;
    @Resource
    private AccountService accountService;
    @Resource
    private TokenProvider tokenProvider;
    @Resource
    private UniqueSnowFlakeGenerate uniqueSnowFlakeGenerate;
    @Autowired
    private IGroupUserCoreService groupUserCoreService;
    @Autowired
    private UserChannelClient userChannelClient;
    /**
     * 创建用户
     *
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = EhcacheConstant.USER)
    public UserVo createUser(UserFrom user) {
        UserEntity entity = BeanUtil.copyProperties(user,UserEntity.class);
        entity.setAccount(uniqueSnowFlakeGenerate.getSerialId(UniqueTypeGenerateEnums.xim_USER.getCode()));
        userService.save(entity);
        AccountEntity account = new AccountEntity();
        //salt
        String salt = RandomStringUtils.randomAlphanumeric(20);
        account.setSalt(salt);
        account.setUserId(entity.getId());
        account.setPassword(MD5Encoder.encode((user.getPassword()+salt).getBytes()));
        account.setAccount(user.getUserName());
        account.setSso(user.getSso());
        accountService.save(account);
        AccountDto dto = new AccountDto();
        BeanUtils.copyProperties(account,dto);
        UserVo vo = new UserVo();
        BeanUtils.copyProperties(entity,vo);
        vo.setAccountVo(dto);
        return vo;
    }

    /**
     * 查询用户信息
     *
     * @param userId
     * @return
     */
    @Override
    @Cacheable(value = EhcacheConstant.USER)
    public UserVo find(Long userId) {
        UserEntity entity = userService.getById(userId);
        if (entity != null) {
            UserVo vo = new UserVo();
            BeanUtils.copyProperties(entity,vo);
            return vo;
        }
        return null;
    }

    /**
     * 查询用户信息
     *
     * @param account
     * @return
     */
    @Override
    @Cacheable(value = EhcacheConstant.USER)
    public UserVo find(String account) {
        UserEntity entity = userService.getEntityByAccount(account);
        if (entity != null) {
            UserVo vo = new UserVo();
            BeanUtils.copyProperties(entity,vo);
            return vo;
        }
        return null;
    }

    /**
     * 查询用户信息
     *
     * @param account
     * @return
     */
    @Override
    @Cacheable(value = EhcacheConstant.USER)
    public UserEntity getUnique(String account) {
        return userService.getEntityByAccount(account);
    }

    /**
     * 批量查询
     *
     * @param ids
     * @return
     */
    @Override
    @Cacheable(value = EhcacheConstant.USER)
    public List<UserVo> batchFindById(Collection ids) {
        List<UserVo> vos = new ArrayList<>();
        List <UserEntity>userList = userService.listByIds(ids);
        if(userList.isEmpty()){
            return new ArrayList<>();
        }
        for (UserEntity userEntity : userList) {
            UserVo vo =new UserVo();
            BeanUtils.copyProperties(userEntity,vo);
            vos.add(vo);
        }
        return vos;
    }

    /**
     * 批量查询
     *
     * @param ids
     * @return
     */
    @Override
    @Cacheable(value = EhcacheConstant.USER)
    public List<UserVo> batchFindByAccount(Collection<String> ids) {
        if(ids.isEmpty()){
            return new ArrayList<>();
        }
        List<UserVo> userVos = new ArrayList<>();
        List<UserEntity> entities = userService.lambdaQuery().in(UserEntity::getAccount, ids).list();
        for (UserEntity entity : entities) {
            UserVo user = new UserVo();
            BeanUtils.copyProperties(entity,user);
            userVos.add(user);
        }
        return userVos;
    }

    /**
     * 批量创建用户
     *
     * @param users
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = EhcacheConstant.USER)
    public Boolean batchCreateUser(List<UserFrom> users) {
        for (UserFrom user : users) {
            UserEntity entity = BeanUtil.copyProperties(user,UserEntity.class);

            entity.setAccount(uniqueSnowFlakeGenerate.getSerialId(UniqueTypeGenerateEnums.xim_USER.getCode()));
            userService.save(entity);
            AccountEntity account = new AccountEntity();
            //salt
            String salt = RandomStringUtils.randomAlphanumeric(20);
            account.setSalt(salt);
            account.setUserId(entity.getId());
            account.setPassword(MD5Encoder.encode((user.getPassword()+salt).getBytes()));
            account.setAccount(user.getUserName());
            account.setSso(user.getSso());
            accountService.save(account);
        }
        return true;
    }

    /**
     * 修改用户信息
     *
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = EhcacheConstant.USER)
    public Boolean updateUserInfo(UserFrom user) {

        UserEntity userEntity = userService.getEntityByAccount(user.getAccount());
        if (userEntity != null) {
            UserEntity entity = new UserEntity();
            entity.setId(userEntity.getId());
            entity.setAvatarUrl(user.getAvatarUrl());
            entity.setNickname(user.getNickname());
            entity.setSignature(user.getSignature());
            userService.updateById(entity);
            Set<String> connections = ChannelClientContextUtil.getAllConnections(userEntity.getAccount());
            if(!connections.isEmpty()){
                for (String ctxId : connections) {
                    SessionUser session = userChannelClient.session(ctxId);
                    session.setAvatarUrl(user.getAvatarUrl());
                    session.setNickname(user.getNickname());
                    session.setSignature(user.getSignature());
                    userChannelClient.bindSession(session,ctxId);
                }
            }
        }
        return Boolean.TRUE;
    }

    /**
     * 修改用户密码
     *
     * @param user
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = EhcacheConstant.USER)
    public Boolean updatePassword(UserFrom user) {
        UserEntity userEntity = userService.getEntityByAccount(user.getAccount());
        if (userEntity != null) {
            AccountEntity entity = accountService.getEntityByUserId(userEntity.getId());
            entity.setPassword(MD5Encoder.encode((user.getPassword()+entity.getSalt()).getBytes()));
            accountService.updateById(entity);
            //修改完用户密码强制下线
            kickOut(user);
            return Boolean.TRUE;
        }
        return Boolean.FALSE;

    }

    /**
     * 踢出在线用户
     *
     * @param user
     */
    @Override
    public Boolean kickOut(UserFrom user) {
        UserEntity entity = userService.getEntityByAccount(user.getAccount());
        if (entity != null) {
            UserDto dto = UserDto.builder()
                    .id(entity.getId())
                    .orgId(user.getOrgId())
                    .account(user.getAccount())
                    .build();
            tokenProvider.invalid(dto);
            ChannelClientContextUtil.unbindingChannel(user.getAccount());
            return Boolean.TRUE;
        }else {
            throw new BusinessException("当前用户不存在");
        }

    }

    /**
     * 禁言
     * 默认俩个小时
     * @param user
     */
    @Override
    public void mute(UserFrom user) {
        Long time = Long.valueOf(60 * 60 * 2);
        GroupUserDto groupUserDto = new GroupUserDto();
        groupUserDto.setGroupUniqueId(user.getGroupUniqueId());
        groupUserDto.setUserAccount(user.getAccount());
        groupUserCoreService.shutUpUser(time,groupUserDto);
    }

    /**
     * 移除禁言
     * @param user
     */
    @Override
    public void removeMute(UserFrom user) {
        GroupUserDto groupUserDto = new GroupUserDto();
        groupUserDto.setGroupUniqueId(user.getGroupUniqueId());
        groupUserDto.setUserAccount(user.getAccount());
        groupUserCoreService.unmute(groupUserDto);
    }

    /**
     * 是否禁言
     *
     * @param user
     * @return  true 禁言  false 未禁言
     */
    @Override
    public Boolean isMute(UserFrom user) {
        GroupUserDto groupUserDto = new GroupUserDto();
        groupUserDto.setGroupUniqueId(user.getGroupUniqueId());
        groupUserDto.setUserAccount(user.getAccount());
        return groupUserCoreService.existMute(groupUserDto);
    }

}
